﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace CatsAndMice.Models
{

    public enum Difficulty { EASY, MEDIUM, HARD }

    public class Game : AbstractModel
    {
        
        public Game(int id, List<Mouse> players, int boardLength, Difficulty difficulty)
            : base(id)
        {
            _dice = new Dice();
            _players = players;
            _nextPlayerEnumerator = _players.GetEnumerator();
            _boardLength = boardLength;
            _difficulty = difficulty;
            _lastField = boardLength * boardLength;
            GenerateElephants();
            GenerateCats();
        }

        #region Board length
        private int _boardLength;
        private readonly int _lastField;
        public int BoardLength
        {
            get
            {
                return _boardLength;
            }
        }
        #endregion

        #region Current player
        private Mouse _currentPlayer;
        public Mouse CurrentPlayer
        {
            get
            {
                return _currentPlayer;
            }
            set
            {
                SetProperty(ref _currentPlayer, value, () => CurrentPlayer);
            }
        }
        #endregion

        #region Next player
        private IEnumerator<Mouse> _nextPlayerEnumerator;
        public Mouse NextPlayer
        {
            get
            {
                if (!_nextPlayerEnumerator.MoveNext())
                {
                    _nextPlayerEnumerator.Reset();
                    _nextPlayerEnumerator.MoveNext();
                }
                return _nextPlayerEnumerator.Current;
            }
        }
        #endregion

        #region Players
        private List<Mouse> _players;
        public List<Mouse> Players
        {
            get
            {
                return _players;
            }
        }
        #endregion

        #region Dice
        private Dice _dice;
        public Dice Dice
        {
            get
            {
                return _dice;
            }
        }
        #endregion

        #region Difficulty
        private Difficulty _difficulty;
        public Difficulty Difficulty
        {
            get
            {
                return _difficulty;
            }
        }
        #endregion

        #region Elephants & cats
        private Dictionary<int, Elephants> _elephants;
        public Dictionary<int, Elephants> Elephants
        {
            get
            {
                return _elephants;
            }
        }
        private Dictionary<int, Cat> _cats;
        public Dictionary<int, Cat> Cats
        {
            get
            {
                return _cats;
            }
        }
        #endregion

        public int CalculateTargetPositionForCurrentPlayer()
        {
            int targetPos = CurrentPlayer.TargetPosition + Dice.Value;
            
            Portal p = null;
            if (Elephants.ContainsKey(targetPos))
            {
                p = Elephants[targetPos];
            }
            else if (Cats.ContainsKey(targetPos))
            {
                p = Cats[targetPos];
            }

            if (p != null)
                targetPos = p.EndPos;

            return targetPos;
        }

        /// <summary>
        /// Reasons for a player not being able to move are:
        /// - at the beginning, he/she hasn't rolled a 6 yet
        /// - in the end, he/she rolled a number greater than the count of remaining fields
        /// </summary>
        /// <returns>whether the current player may actually move his figure</returns>
        public bool MayCurrentPlayerMove()
        {
            bool mayStart = CurrentPlayer.MayMove || Dice.Value == Dice.MAX_VALUE;
            bool noOverflow = (CurrentPlayer.TargetPosition + Dice.Value) <= _lastField;
#if DEBUG
            Console.WriteLine("may start: {0} - no overflow: {1}", mayStart, noOverflow);
#endif
            return mayStart && noOverflow;
        }

        private void GenerateElephants()
        {
            _elephants = new Dictionary<int, Elephants>();
        }

        private void GenerateCats()
        {
            _cats = new Dictionary<int, Cat>();
        }

        #region Statistical data, will be instrumented later
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
        #endregion

        public override string ToString()
        {
            return "Game with id "+ID+".\nIt is "+CurrentPlayer+"'s turn." ;
        }
    }
}
